package com.sc.demo.plugins;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.log4j.Logger;

import com.sc.demo.annotation.Master;
import com.sc.demo.util.CamelToUnderlineUtil;


/**    
 *     
 * 项目名称：51credit-core-service    
 * 类名称：MasterSlaveAutoRouterPlugin    
 * 类描述：    读写分离路由（配合mysql Replication driver）
 * 创建人：huan    
 * 创建时间：2016年8月29日 下午5:03:41    
 * 修改人：huan    
 * 修改时间：2016年8月29日 下午5:03:41    
 * 修改备注：    
 * @version     
 *     
 */
@Intercepts({
	@Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
	@Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class})
})
public class MasterSlaveAutoRouterPlugin implements Interceptor {
	
    private static final String QUERY = "query";

	
	private Logger logger = Logger.getLogger(MasterSlaveAutoRouterPlugin.class);
	
	@SuppressWarnings({ "unchecked", "rawtypes" })
    public Object intercept(Invocation invocation) throws Throwable {
	    MappedStatement mappedStatement = (MappedStatement)invocation.getArgs()[0];
		String sqlId = mappedStatement.getId();
		boolean isMapUnderscoreToCamelCase = mappedStatement.getConfiguration().isMapUnderscoreToCamelCase();
		logger.debug("[MasterSlaveRouterPlugin] Class   = " + sqlId.substring(0, sqlId.lastIndexOf('.')));
		logger.debug("[MasterSlaveRouterPlugin] Method  = " + ((MappedStatement)invocation.getArgs()[0]).getId());
		String daoClassName = sqlId.substring(0, sqlId.lastIndexOf('.'));
		String methodName = sqlId.substring(sqlId.lastIndexOf('.')+1);
		String iMethodName = invocation.getMethod().getName();
		
		boolean isReadOnly = false;
		Method[] methods= Class.forName(daoClassName).getMethods();
		for(Method method : methods){
			if(method.getName().equals(methodName)){
			    Master master = method.getAnnotation(Master.class);
				if( QUERY.equals(iMethodName)  && null == master){
				    isReadOnly = true;
					break;
				}
			}
		}
		//切换到从库
		((Executor)invocation.getTarget()).getTransaction().getConnection().setReadOnly(isReadOnly);
		Object o = invocation.proceed();
		//是否开启自动驼峰命名规则（camel case）映射
		if(isMapUnderscoreToCamelCase && null != o  ){
		    List<Map<String , Object>> resultList = new ArrayList<Map<String , Object>>();
		    for(Object temp: (List)o){
		        if(temp instanceof Map){
		            Map<String , Object> tempMap = (Map<String, Object>) temp;
		            Map<String , Object> resultMap = new HashMap<String , Object>();
		            for(String key: tempMap.keySet()){
		                resultMap.put(CamelToUnderlineUtil.underlineToCamel(key), tempMap.get(key));
		            }
		            resultList.add(resultMap);
		            o =  resultList;
		        }
		    }
		}
		//切换回主库，防止写操作失败
		((Executor)invocation.getTarget()).getTransaction().getConnection().setReadOnly(false);
		return o;
	}

	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	public void setProperties(Properties properties) {
	}
}
